<?php if (!defined('DEDEINC')) {
    exit("DedeCMS Error: Request Error!");
}

/**
 *  本类用于指定一个 MySQL 的数据表
 *  自动生成列出、修改、删除、增加等操作
 *
 *   2011-11-08 [完善]对LURD类进行如下完善
 *        1.增加单条记录管理功能,指定$lurd->singleManage=TRUE,增加单条记录的管理页面;
 *        2.修改LURD默认管理页面的体验;
 *        3.模板页面支持~self~指向当前页地址;
 *        4.lurd支持get模式,便于单条记录的管理;
 *   2010-11-17 [修复]启用request类默认数据处理问题
 *   2010-11-17 [修复]如果存在UNIQUE表字段分析错误的问题
 *   2010-11-17 [增加]增加检索条件匹配方法
 *   2010-11-16 [增加]如果表字段存在注释,则列表项的title中则直接显示注释信息
 *   2010-11-14 [修复]数据表存在前缀,模板名称解析问题,同时可以对Lurd单独设定模板
 *
 * @version   $Id: lurd.class.php 7 14:07 2011/11/8 IT柏拉图, $
 * @package   DedeCMS.Libraries
 * @founder   IT柏拉图, https://weibo.com/itprato
 * @author    DedeCMS团队
 * @copyright Copyright (c) 2007 - 2021, 上海卓卓网络科技有限公司 (DesDev, Inc.)
 * @license   http://help.dedecms.com/usersguide/license.html
 * @link      http://www.dedecms.com
 */

require_once DEDEINC . '/datalistcp.class.php';

/***********************************
@ class lurd
 ***********************************/
class Lurd extends DataListCP
{
    // 固定属性
    public $dateTypes = array('DATE', 'DATETIME', 'TIMESTAMP', 'TIME', 'YEAR');
    public $floatTypes = array('FLOAT', 'DOUBLE', 'DECIMAL');
    public $intTypes = array('TINYINT', 'SMALLINT', 'MEDIUMINT', 'INT', 'BIGINT');
    public $charTypes = array('VARCHAR', 'CHAR', 'TINYTEXT');
    public $textTypes = array('TEXT', 'MEDIUMTEXT', 'LONGTEXT');
    public $binTypes = array('TINYBLOB', 'BLOB', 'MEDIUMBLOB', 'LONGBLOB', 'BINARY', 'VARBINARY');
    public $emTypes = array('ENUM', 'SET');
    // 普通属性
    public $tableName = '';
    public $templateDir = '';
    public $lurdTempdir = '';
    public $tplName = '';
    public $appName = '';
    public $primaryKey = '';
    public $autoField = '';
    public $orderQuery = '';
    // 所的字段及属性数组
    public $fields = array();
    // 当这个值为TRUE，每次都会生成新模板，用于调试模式
    public $isDebug = false;
    // 文本内容安全级别
    // 0 为不处理， 1 为禁止不安全HTML内容(javascript等)，2完全禁止HTML内容，并替换部份不安全字符串（如：eval(、union、CONCAT(、--、等）
    public $stringSafe = 1;
    // 这个变量用于存放连结表的参数
    // 可以通过 $lurd->AddLinkTable($tablelurd, linkfields, mylinkid, linkid); 联结一个表
    public $linkTables = array();
    // 联结表的指定字段(如果后一个表的字段和前一个重名, 前者会被替换)
    public $addFields = array();
    // 查询条件
    public $searchParameters = array();

    // 单条记录管理,修改/删除
    public $singleManage = true;

    //构造函数，指定要操作的表名
    public function __construct($tablename, $templatedir = '', $lurdtempdir = '')
    {
        global $dsql;
        $prefix = "#@__";
        $this->tplName = str_replace($prefix, '', $tablename);
        $this->tableName = str_replace($prefix, $GLOBALS['cfg_dbprefix'], $tablename);
        $this->templateDir = $templatedir;
        $this->lurdTempdir = empty($lurdtempdir) ? $this->templateDir . '/lurd' : $lurdtempdir;
        parent::__construct();
        $this->AnalyseTable();
        $ct = isset($GLOBALS['ct']) ? $GLOBALS['ct'] : request('ct', '');
        if (!empty($ct)) {
            $this->SetParameter('ct', $ct);
        }
        $this->SetParameter('ac', 'list');
    }

    //监听器，根据指定的ac(ac)调用相应处理方法
    public function ListenAll($listfield = '', $wherequery = '', $orderquery = '')
    {
        global $action;
        $action = !empty($action) ? $action : request('action');
        switch ($action) {
        case 'add':
            $this->AddData();
            break;
        case 'edit':
            $this->EditData();
            break;
        case 'del':
            $this->DelData();
            break;
        case 'saveadd':
            $this->SaveAddData();
            break;
        case 'saveedit':
            $this->SaveEditData();
            break;
        default:
            $this->ListData($listfield, $wherequery, $orderquery);
            break;
        }
    }

    // 指定主键
    // 在数据表没有主键的情况下，必须指定一个字段为主键字段，否则系统用所有数据的md5值作为主键
    public function AddPriKey($fieldname)
    {
        $this->primaryKey = $fieldname;
    }

    // 指定应用的名称
    public function AddAppName($appname)
    {
        $this->appName = $appname;
    }

    //设置用于排序的SQL，如 order by id desc
    public function SetOrderQuery($query)
    {
        $this->orderQuery = $query;
    }

    //强制指定字段为其它类型
    public function BindType($fieldname, $ftype, $format = '')
    {
        //'type' =>'','length' =>'0','unsigned'=>FALSE,'autokey'=>FALSE,
        //'null'=>FALSE,default'=>'','em'=>'','format'=>'','listtemplate'=>'','edittemplate'=>''
        $typesArr = array_merge($this->dateTypes, $this->floatTypes, $this->intTypes, $this->charTypes, $this->textTypes, $this->binTypes, $this->emTypes);
        if (isset($this->fields[$fieldname]) && in_array(strtoupper($ftype), $typesArr)) {
            $this->fields[$fieldname]['type'] = $ftype;
            $this->fields[$fieldname]['format'] = $format;
        }
    }

    //强制指定字模板（列表list和编辑edit、增加add模板里用）
    public function BindTemplate($fieldname, $tmptype = 'list', $temp = '')
    {
        if (isset($this->fields[$fieldname])) {
            $this->fields[$fieldname][$tmptype . 'template'] = $temp;
        }
    }

    // 列出数据
    /*********************************
     * $listfield = '' 指定要列出的字段(默认为'*') ，只需填写当前表
    联结表出的字段在 AddLinkTable 指定， 因此不需要 表名.字段名 方式识别
     * $wherequery = '' 查询query，如果联结了其它表，需用 表名.字段名 识别字段
     * $orderquery = '' 排序query，如果联结了其它表，需用 表名.字段名 识别字段
     **********************************/
    public function ListData($listfield = '*', $wherequery = '', $orderquery = '', $Suff = '_list.htm')
    {
        $listdd = '';
        if (trim($listfield) == '') {
            $listfield = '*';
        }

        $template = $this->templateDir . '/' . $this->tplName . $Suff;
        //生成列表模板
        if (!file_exists($template) || $this->isDebug) {
            $this->MakeListTemplate($listfield);
        }

        // 获取检索条件
        if ($wherequery == '') {
            $wherequery = $this->GetSearchQuery();
        }

        //是否有联结其它的表
        $islink = count($this->linkTables) > 0 ? true : false;
        //主表索引字段(Select * From 部份)
        $listfields = explode(',', $listfield);
        foreach ($listfields as $v) {
            $v = trim($v);
            if (!isset($this->fields[$v]) && $v != '*') {
                continue;
            }

            if ($islink) {
                $listdd .= ($listdd == '' ? "{$this->tableName}.{$v}" : ", {$this->tableName}.{$v} ");
            } else {
                if ($v == '*') {
                    $listdd .= ' * ';
                } else {
                    $listdd .= ($listdd == '' ? "`$v`" : ",`$v`");
                }

            }
        }
        if ($listdd == '') {
            $listdd = " * ";
        }

        //联结表索引字段
        if ($islink) {
            $joinQuery = '';
            foreach ($this->linkTables as $k => $linkTable) {
                $k++;
                $linkTableName = $linkTable[0]->tableName;
                $joinQuery .= " LEFT JOIN `{$linkTableName}` ON {$linkTableName}.{$linkTable[2]} = {$this->tableName}.{$linkTable[1]} ";
                foreach ($this->addFields as $f => $v) {
                    if ($v['table'] != $linkTableName) {
                        continue;
                    }

                    $listdd .= ", {$linkTableName}.{$f} ";
                }
            }
            $query = "SELECT $listdd FROM `{$this->tableName}` $joinQuery $wherequery $orderquery ";
        } else {
            $query = "SELECT $listdd FROM `{$this->tableName}` $wherequery $orderquery ";
        }

        $this->SaveCurUrl();
        $this->SetTemplate($template);
        $this->SetSource($query);
        $this->Display();
    }

    //记录列表网址到cookie，方便返回时调用
    public function SaveCurUrl()
    {
        setcookie('LURD_GOBACK_URL', $this->GetCurFullUrl(), time() + 3600, '/');
    }

    public function GetCurFullUrl()
    {
        if (!empty($_SERVER["REQUEST_URI"])) {
            $scriptName = $_SERVER["REQUEST_URI"];
            $nowurl = $scriptName;
        } else {
            $scriptName = $_SERVER["PHP_SELF"];
            $nowurl = empty($_SERVER["QUERY_STRING"]) ? $scriptName : $scriptName . "?" . $_SERVER["QUERY_STRING"];
        }
        return $nowurl;
    }

    //生成全部模板
    public function MakeAllTemplate($listfield = '')
    {
        $this->MakeListTemplate($listfield);
        $this->MakeAddEditTemplate('add');
        $this->MakeAddEditTemplate('edit');
    }

    //生成列表模板
    public function MakeListTemplate($listfield = '')
    {
        $templateTemplate = $this->lurdTempdir . '/lurd-list.htm';
        $template = $this->templateDir . '/' . $this->tplName . '_list.htm';
        $tempstr = '';
        $fp = fopen($templateTemplate, 'r');
        while (!feof($fp)) {
            $tempstr .= fread($fp, 1024);
        }

        fclose($fp);
        $tempItems = array('appname' => '', 'totalitem' => '', 'titleitem' => '', 'fielditem' => '');
        $tempItems['appname'] = empty($this->appName) ? "管理数据表： " . $this->tableName : $this->appName;
        //设置选择项
        $tempItems['totalitem'] = 1;
        $tempItems['self'] = $_SERVER["PHP_SELF"];
        $titleitem = "    <td class='nowrap'>选择</td>\r\n";
        if (!preg_match("/,/", $this->primaryKey)) {
            $fielditem = "    <td class='nowrap'><input type=\"checkbox\" name=\"{$this->primaryKey}[]\" value=\"{dede:field name='{$this->primaryKey}' /}\" /></td>\r\n";
        } else {
            $prikeys = explode(',', $this->primaryKey);
            $prikeyValue = '<' . '?php echo md5("key"';
            foreach ($prikeys as $v) {
                $prikeyValue .= '.$fields["' . $v . '"]';
            }
            $prikeyValue .= '); ?' . '>';
            $fielditem = "    <td class='nowrap'><input type=\"checkbox\" name=\"primarykey[]\" value=\"{$prikeyValue}\" /></td>\r\n";
        }
        //使用手工指定列出字段
        if (!empty($listfield) && $listfield != '*') {
            $listfields = explode(',', $listfield);
            $tempItems['totalitem'] = count($listfields) + 1;
            foreach ($listfields as $k) {
                $k = trim($k);
                if (!isset($this->fields[$k])) {
                    continue;
                }

                $v = $this->fields[$k];
                $title = !empty($v['comment']) ? $v['comment'] : $k;
                $titleitem .= "    <td class='nowrap'>$title</td>\r\n";
                if (!empty($v['listtemplate'])) {
                    $fielditem .= "    <td class='nowrap'>{$v['listtemplate']}</td>\r\n";
                } else {
                    $dofunc = $dtype = $fformat = '';
                    $dtype = !empty($v['type']) ? $v['type'] : 'check';
                    if (isset($v['format'])) {
                        $fformat = $v['format'];
                    }
                    if (isset($v['dofunc'])) {
                        $dofunc = $v['dofunc'];
                    }
                    if (isset($v['type'])) {
                        $this->fields[$k]['type'] = $v['type'];
                    }
                    if (in_array($v['type'], $this->floatTypes)) {
                        $dtype = 'float';
                        $dofunc = ($dofunc == '' ? "function=\"Lurd::FormatFloat(@me, '$fformat')\"" : '');
                    }
                    if (in_array($v['type'], $this->dateTypes)) {
                        $dtype = 'date';
                        $dofunc = ($dofunc == '' ? "function=\"Lurd::FormatDate(@me, '{$this->fields[$k]['type']}', '$fformat')\"" : '');
                    }
                    $fielditem .= "    <td class='nowrap'>{dede:field name='{$k}' $dofunc /}</td>\r\n";
                }
            } //End foreach
        }
        //自动处理
        else {
            foreach ($this->fields as $k => $v) {
                if (in_array($v['type'], $this->binTypes)) {
                    continue;
                }
                $tempItems['totalitem']++;
                $title = !empty($v['comment']) ? $v['comment'] : $k;
                $titleitem .= "    <td class='nowrap'>$title</td>\r\n";
                $dofunc = $dtype = $fformat = '';
                if (isset($v['format'])) {
                    $fformat = $v['format'];
                }
                if (in_array($v['type'], $this->floatTypes)) {
                    $dtype = 'float';
                    $dofunc = ($dofunc == '' ? "function=\"Lurd::FormatFloat(@me, '$fformat')\"" : '');
                }
                if (in_array($v['type'], $this->dateTypes)) {
                    $dtype = 'date';
                    $dofunc = ($dofunc == '' ? "function=\"Lurd::FormatDate(@me, '{$this->fields[$k]['type']}', '$fformat')\"" : '');
                }
                $fielditem .= "    <td class='nowrap'>{dede:field name='{$k}' $dofunc /}</td>\r\n";
            }
        }

        //是否有联结其它的表
        $islink = count($this->linkTables) > 0 ? true : false;
        //附加表的字段
        if ($islink) {
            foreach ($this->addFields as $k => $v) {
                if (in_array($v['type'], $this->binTypes)) {
                    continue;
                }
                $tempItems['totalitem']++;
                $titleitem .= "    <td class='nowrap'>$k</td>\r\n";
                $dofunc = $dtype = $fformat = '';
                if (in_array($v['type'], $this->floatTypes)) {
                    $dtype = 'float';
                    $dofunc = ($dofunc == '' ? "function=\"Lurd::FormatFloat(@me, '$fformat')\"" : '');
                }
                if (in_array($v['type'], $this->dateTypes)) {
                    $dtype = 'date';
                    $dofunc = ($dofunc == '' ? "function=\"Lurd::FormatDate(@me, '{$this->fields[$k]['type']}', '$fformat')\"" : '');
                }
                $fielditem .= "    <td class='nowrap'>{dede:field name='{$k}' $dofunc /}</td>\r\n";
            }
        }

        if ($this->singleManage) {
            $tempItems['totalitem']++;
            $titleitem .= "    <td class='nowrap'>管理</td>\r\n";
            $currentUrl = $this->GetCurUrl();
            $fielditem .= "    <td class='nowrap'>
			<a href=\"{$currentUrl}?{$this->primaryKey}={dede:field name='{$this->primaryKey}' /}&ac=edit&get=yes\">修改</a>
			|  <a href=\"{$currentUrl}?{$this->primaryKey}={dede:field name='{$this->primaryKey}' /}&ac=del&get=yes\">删除</a> </td>\r\n";
        }

        $tempItems['titleitem'] = $titleitem;
        $tempItems['fielditem'] = $fielditem;
        foreach ($tempItems as $k => $v) {
            $tempstr = str_replace("~$k~", $v, $tempstr);
        }
        $fp = fopen($template, 'w');
        fwrite($fp, $tempstr);
        fclose($fp);
    }

    //生成发布或编辑模板
    public function MakeAddEditTemplate($getTemplets = 'add')
    {
        $templateTemplate = $this->lurdTempdir . "/lurd-{$getTemplets}.htm";
        $template = $this->templateDir . '/' . $this->tplName . "_{$getTemplets}.htm";
        $tempstr = '';
        $fp = fopen($templateTemplate, 'r');
        while (!feof($fp)) {
            $tempstr .= fread($fp, 1024);
        }

        fclose($fp);
        $tempItems = array('appname' => '', 'fields' => '', 'primarykey' => '');
        $tempItems['appname'] = empty($this->appName) ? "在 {$this->tableName} " . ($getTemplets == 'add' ? '添加数据' : '编辑数据') : $this->appName;
        $tempItems['fields'] = '';
        $tempItems['self'] = $_SERVER["PHP_SELF"];
        if (!preg_match("/,/", $this->primaryKey)) {
            $tempItems['primarykey'] = "    <input type=\"hidden\" name=\"{$this->primaryKey}\" value=\"{dede:field name='{$this->primaryKey}' /}\" />\r\n";
        } else {
            $prikeys = explode(',', $this->primaryKey);
            $prikeyValue = '<' . '?php echo md5("key"';
            foreach ($prikeys as $v) {
                $prikeyValue .= '.$fields["' . $v . '"]';
            }
            $prikeyValue .= '); ?' . '>';
            $tempItems['primarykey'] = "    <input type=\"hidden\" name=\"primarykey[]\" value=\"{$prikeyValue}\" />\r\n";
        }
        $fielditem = '';
        foreach ($this->fields as $k => $v) {
            $aeform = $dtype = $defaultvalue = $fformat = '';
            $title = !empty($v['comment']) ? $v['comment'] : $k;
            //在指定了字段模板情况下不使用自动生成
            if (isset($this->fields[$k][$getTemplets . 'template'])) {
                $fielditem .= $this->fields[$k][$getTemplets . 'template'];
                continue;
            }
            //排除自动递增键
            if ($k == $this->autoField) {
                continue;
            }
            //编辑时，排除主键
            if ($k == $this->primaryKey && $getTemplets == 'edit') {
                continue;
            }
            //格式化选项(编辑时用)
            if (isset($this->fields[$k]['format'])) {
                $fformat = $this->fields[$k]['format'];
            }
            //获得字段默认值（编辑时从数据库获取）
            if ($getTemplets == 'edit') {
                if (in_array($this->fields[$k]['type'], $this->binTypes)) {
                    $dfvalue = '';
                } else {
                    $dfvalue = "{dede:field name='$k' /}";
                }

            } else {
                $dfvalue = $this->fields[$k]['default'];
            }
            //小数类型
            if (in_array($this->fields[$k]['type'], $this->floatTypes)) {
                if ($getTemplets == 'edit') {
                    $dfvalue = "{dede:field name='$k' function=\"Lurd::FormatFloat(@me, '$fformat')\" /}";
                } else if ($this->fields[$k]['default'] == '') {
                    $dfvalue = 0;
                }
                $aeform = "<input type='input' name='{$k}' class='txtnumber' value='$dfvalue' />";
            }
            //整数类型
            if (in_array($this->fields[$k]['type'], $this->intTypes)) {
                $aeform = "<input type='input' name='{$k}' class='txtnumber' value='$dfvalue' />";
            }
            //时间类型
            else if (in_array($this->fields[$k]['type'], $this->dateTypes)) {
                if (empty($fformat)) {
                    $fformat = 'Y-m-d H:i:s';
                }

                if ($getTemplets == 'edit') {
                    $dfvalue = "{dede:field name='$k' function=\"MyDate(@me, '$fformat')\" /}";
                } else if (empty($this->fields[$k]['default'])) {
                    $dfvalue = "{dede:var.a function=\"MyDate(time(), '$fformat')\" /}";
                }
                $aeform = "<input type='input' name='{$k}' class='txtdate' value='$dfvalue' />";
            }
            //长文本类型
            else if (in_array($this->fields[$k]['type'], $this->textTypes)) {
                $aeform = "<textarea name='$k' class='txtarea'>{$dfvalue}</textarea>";
            }
            //二进制类型
            else if (in_array($this->fields[$k]['type'], $this->textTypes)) {
                $aeform = "<input type='file' name='$k' size='45' />";
            }
            //SET类型
            else if ($this->fields[$k]['type'] == 'SET') {
                $ems = explode(',', $this->fields[$k]['em']);
                if ($getTemplets == 'edit') {
                    $aeform .= '<' . '?php $enumItems = explode(\',\', $fields[\'' . $k . '\']); ?' . '>';
                }
                foreach ($ems as $em) {
                    if ($getTemplets == 'add') {
                        $aeform .= "<input type='checkbox' name='{$k}[]' value='$em' />$em \r\n";
                    } else {
                        $aeform .= "<input type='checkbox' name='{$k}[]' value='$em' {dede:if in_array('$em', \$enumItems)}checked{/dede:if} />$em \r\n";
                    }
                }
            }
            //ENUM类型
            else if ($this->fields[$k]['type'] == 'ENUM') {
                $ems = explode(',', $this->fields[$k]['em']);
                foreach ($ems as $em) {
                    if ($getTemplets == 'edit') {
                        $aeform .= "<input type='radio' name='$k' value='$em' {dede:if \$fields['$k']}=='$em'}checked{/dede:if} />$em \r\n";
                    } else {
                        $aeform .= "<input type='radio' name='$k' value='$em' />$em \r\n";
                    }
                }
            } else {
                $aeform = "<input type='input' name='{$k}' class='txt' value='$dfvalue' />";
            }
            $fielditem .= "    <tr>\r\n<td height='28' align='center' bgcolor='#FFFFFF'>{$title}</td>\r\n<td bgcolor='#FFFFFF'>{$aeform}</td>\r\n</tr>\r\n";
        }
        $tempItems['fields'] = $fielditem;
        foreach ($tempItems as $k => $v) {
            $tempstr = str_replace("~$k~", $v, $tempstr);
        }
        $fp = fopen($template, 'w');
        fwrite($fp, $tempstr);
        fclose($fp);
    }

    // 读取数据
    public function EditData()
    {
        $template = $this->templateDir . '/' . $this->tplName . '_edit.htm';
        //生成列表模板
        if (!file_exists($template) || $this->isDebug) {
            $this->MakeAddEditTemplate('edit');
        }
        $whereQuery = '';
        $GLOBALS[$this->primaryKey] = isset($GLOBALS[$this->primaryKey]) ? $GLOBALS[$this->primaryKey] : request($this->primaryKey);
        if (empty($GLOBALS['primarykey'][0]) && empty($GLOBALS[$this->primaryKey][0])) {
            ShowMsg('请选择要修改的记录！', '-1');
            exit();
        }
        if (preg_match("/,/", $this->primaryKey)) {
            $whereQuery = "WHERE md5(CONCAT('key', `" . str_replace(',', '`,`', $this->primaryKey) . "`) = '{$GLOBALS['primarykey'][0]}' ";
        } else {
            $pkey = (request('get') == 'yes') ? request($this->primaryKey) : $GLOBALS[$this->primaryKey][0];
            $whereQuery = "WHERE `{$this->primaryKey}` = '" . $GLOBALS[$this->primaryKey][0] . "' ";
        }

        //列出数据
        $query = "SELECT * FROM `{$this->tableName}` $whereQuery ";
        $this->SetTemplate($template);
        $this->SetSource($query);
        $this->Display();
    }

    // 新增数据
    public function AddData()
    {
        $template = $this->templateDir . '/' . $this->tplName . '_add.htm';
        //生成列表模板
        if (!file_exists($template) || $this->isDebug) {
            $this->MakeAddEditTemplate('add');
        }
        //生成发布表单数据
        $this->SetTemplate($template);
        $this->Display();
        exit();
    }

    // 保存新增数据
    public function SaveAddData($isturn = true)
    {
        $allfield = $allvalue = '';
        foreach ($this->fields as $k => $v) {
            //自动递增键不处理
            if ($k == $this->autoField) {
                continue;
            }
            $allfield .= ($allfield == '' ? "`$k`" : ' , ' . "`$k`");
            $v = $this->GetData($k);
            $allvalue .= ($allvalue == '' ? "'$v'" : ' , ' . "'$v'");
        }
        $inQuery = "INSERT INTO `$this->tableName`($allfield) VALUES($allvalue); ";
        $rs = $this->dsql->ExecuteNoneQuery($inQuery);

        //只返回结果
        if (!$isturn) {
            return $rs;
        }
        //完全处理模式
        $gourl = !empty($_COOKIE['LURD_GOBACK_URL']) ? $_COOKIE['LURD_GOBACK_URL'] : '-1';
        if (!$rs) {
            $this->dsql->SaveErrorLog($inQuery);
            ShowMsg('保存数据失败，请检查数据库错误日志！', $gourl);
            exit();
        } else {
            ShowMsg('成功保存一组数据！', $gourl);
            exit();
        }
    }

    // 保存编辑数据
    public function SaveEditData($isturn = true)
    {
        $editfield = '';
        foreach ($this->fields as $k => $v) {
            //自动递增键不处理
            $GLOBALS[$k] = isset($GLOBALS[$k]) ? $GLOBALS[$k] : $GLOBALS['request']->forms[$k];
            if ($k == $this->autoField || !isset($GLOBALS[$k])) {
                continue;
            }
            $v = $this->GetData($k);
            $editfield .= ($editfield == '' ? " `$k`='$v' " : ",\n `$k`='$v' ");
        }
        //获得主键值
        if (preg_match("#,#", $this->primaryKey)) {
            $keyvalue = (isset($GLOBALS['primarykey']) ? $GLOBALS['primarykey'] : '');
        } else {
            $keyvalue = $this->GetData($this->primaryKey);
        }
        $keyvalue = preg_replace("#[^0-9a-z]#i", "", $keyvalue);
        if (!preg_match("#,#", $this->primaryKey)) {
            $inQuery = " UPDATE `$this->tableName` SET $editfield WHERE `{$this->primaryKey}`='{$keyvalue}' ";
        } else {
            $inQuery = " UPDATE `$this->tableName` SET $editfield WHERE md5('key', `" . str_replace(',', '`,`', $this->primaryKey) . "`='{$keyvalue}' ";
        }
        $rs = $this->dsql->ExecuteNoneQuery($inQuery);
        //只返回结果
        if (!$isturn) {
            return $rs;
        }
        //完全处理模式
        $gourl = !empty($_COOKIE['LURD_GOBACK_URL']) ? $_COOKIE['LURD_GOBACK_URL'] : '-1';
        if (!$rs) {
            $this->dsql->SaveErrorLog($inQuery);
            ShowMsg('保存数据失败，请检查数据库错误日志！', $gourl);
            exit();
        } else {
            ShowMsg('成功保存一组数据！', $gourl);
            exit();
        }
    }

    //获得当前网址
    public function GetCurUrl()
    {
        if (!empty($_SERVER["REQUEST_URI"])) {
            $nowurl = $_SERVER["REQUEST_URI"];
            $nowurls = explode("?", $nowurl);
            $nowurl = $nowurls[0];
        } else {
            $nowurl = $_SERVER["PHP_SELF"];
        }
        return $nowurl;
    }

    // 删除数据
    public function DelData($isturn = true)
    {
        $GLOBALS[$this->primaryKey] = isset($GLOBALS[$this->primaryKey]) ? $GLOBALS[$this->primaryKey] : request($this->primaryKey);
        if (preg_match("#,#", $this->primaryKey)) {
            $keyArr = (isset($GLOBALS['primarykey']) ? $GLOBALS['primarykey'] : '');
        } else {
            $keyArr = isset($GLOBALS[$this->primaryKey]) ? $GLOBALS[$this->primaryKey] : '';
        }
        if (!is_array($keyArr)) {
            ShowMsg('没指定要删除的记录！', '-1');
            exit();
        } else {
            $isid = !preg_match("#,#", $this->primaryKey) ? true : false;
            $i = 0;
            foreach ($keyArr as $v) {
                $v = preg_replace("#[^0-9a-z]#i", '', $v);
                if (empty($v)) {
                    continue;
                }

                $i++;
                if ($isid) {
                    $this->dsql->ExecuteNoneQuery("DELETE FROM `{$this->tableName}` WHERE `$this->primaryKey`='$v' ");
                } else {
                    $this->dsql->ExecuteNoneQuery("DELETE FROM `{$this->tableName}` WHERE md5('key', `" . str_replace(',', '`,`', $this->primaryKey) . "`='$v' ");
                }
            }
            if ($isturn) {
                $gourl = !empty($_COOKIE['LURD_GOBACK_URL']) ? $_COOKIE['LURD_GOBACK_URL'] : '-1';
                ShowMsg('成功删除指定的记录！', $gourl);
                exit();
            } else {
                return $i;
            }
        }
    }

    //联结其它表(用于数据查询的情况)
    //$tablelurd 目标表lurd对象, $linkfields select的字段
    //$mylinkid 当前表用于联结的字段
    //$linkid 目标表用于联结的字段
    public function AddLinkTable(&$tablelurd, $mylinkid, $linkid, $linkfields = '*')
    {
        if (trim($linkfields) == '') {
            $linkfields = '*';
        }

        $this->linkTables[] = array($tablelurd, $mylinkid, $linkid, $linkfields);
        //记录附加表的字段信息
        if ($linkfields != '*') {
            $fs = explode(',', $linkfields);
            foreach ($fs as $f) {
                $f = trim($f);
                if (isset($tablelurd->fields[$f])) {
                    $this->addFields[$f] = $tablelurd->fields[$f];
                    $this->addFields[$f]['table'] = $tablelurd->tableName;
                }
            }
        } else {
            foreach ($tablelurd->fields as $k => $v) {
                $this->addFields[$k] = $v;
                $this->addFields[$k]['table'] = $tablelurd->tableName;
            }
        }
    }

    //分析表结构
    public function AnalyseTable()
    {
        if ($this->tableName == '') {
            exit(" No Input Table! ");
        }

        $this->dsql->Execute('ana', " SHOW CREATE TABLE `{$this->tableName}`; ");
        $row = $this->dsql->GetArray('ana', MYSQLI_NUM);
        if (!is_array($row)) {
            exit(" Analyse Table `$this->tableName` Error! ");
        }

        // 先去掉内容中的注释
        // $row[1] = preg_replace('#COMMENT \'(.*?)\'#i', '', $row[1]);
        // echo $row[1];exit;
        $flines = explode("\n", $row[1]);
        $parArray = array('date', 'float', 'int', 'char', 'text', 'bin', 'em');
        $prikeyTmp = '';
        for ($i = 1; $i < count($flines) - 1; $i++) {
            $line = trim($flines[$i]);
            $lines = explode(' ', str_replace('`', '', $line));

            if ($lines[0] == 'KEY') {
                continue;
            }

            if ($lines[0] == 'UNIQUE') {
                continue;
            }

            if ($lines[0] == 'PRIMARY') {
                $this->primaryKey = preg_replace("/[\(\)]|,$/", '', $lines[count($lines) - 1]);
                continue;
            }
            //字段名称、类型
            $this->fields[$lines[0]] = array('type' => '', 'length' => '', 'unsigned' => false, 'autokey' => false, 'null' => true, 'default' => '', 'em' => '', 'comment' => '');
            $this->fields[$lines[0]]['type'] = strtoupper(preg_replace("/\(.*$|,/", '', $lines[1]));
            $this->fields[$lines[0]]['length'] = preg_replace("/^.*\(|\)/", '', $lines[1]);
            if (preg_match("#[^0-9]#", $this->fields[$lines[0]]['length'])) {
                if ($this->fields[$lines[0]]['type'] == 'SET'
                    || $this->fields[$lines[0]]['type'] == 'ENUM'
                ) {
                    $this->fields[$lines[0]]['em'] = preg_replace("/'/", '', $this->fields[$lines[0]]['length']);
                }
                $this->fields[$lines[0]]['length'] = 0;
            }

            //把特定类型的数据加入数组中
            foreach ($parArray as $v) {
                $tmpstr = "if(in_array(\$this->fields[\$lines[0]]['type'], \$this->{$v}Types))
                {
                    \$this->{$v}Fields[] = \$lines[0];
                }";
                eval($tmpstr);
            }
            if (!in_array($this->fields[$lines[0]]['type'], $this->textTypes)
                && !in_array($this->fields[$lines[0]]['type'], $this->binTypes)
            ) {
                $prikeyTmp .= ($prikeyTmp == '' ? $lines[0] : ',' . $lines[0]);
            }

            //分析其它属性
            // echo $line;exit;
            if (preg_match("#unsigned#i", $line)) {
                $this->fields[$lines[0]]['unsigned'] = true;
            }
            if (preg_match("#auto_increment#i", $line)) {
                $this->fields[$lines[0]]['autokey'] = true;
                $this->autoField = $lines[0];
            }
            if (preg_match("#NOT NULL#i", $line)) {
                $this->fields[$lines[0]]['null'] = false;
            }
            if (preg_match("#default#i", $line)) {
                preg_match("#default '(.*?)'#i", $line, $dfmatchs);
                $this->fields[$lines[0]]['default'] = isset($dfmatchs[1]) ? $dfmatchs[1] : null;
            }
            if (preg_match("#comment#i", $line)) {
                preg_match("#comment '(.*?)'#i", $line, $cmmatchs);
                $this->fields[$lines[0]]['comment'] = isset($cmmatchs[1]) ? $cmmatchs[1] : null;
            }

        } //end for
        if ($this->primaryKey == '') {
            $this->primaryKey = $prikeyTmp;
        }
    }

    /**
     * 增加搜索条件
     *
     * @parem $fieldname 字段名称
     * @parem $fieldvalue 传入的 value 值必须先经过转义
     * @parem $condition 条件 >、<、=、<> 、like、%like%、%like、like%
     * @parem $linkmode AND 或 OR
     */
    public function AddSearchParameter($fieldname, $fieldvalue, $condition, $linkmode = 'AND')
    {
        $c = count($this->searchParameters);
        //对于指定了多个字段，使用 CONCAT 进行联结（通常是like操作）
        if (preg_match('/,/', $fieldname)) {
            $fs = explode(',', $fieldname);
            $fieldname = "CONCAT(";
            $ft = '';
            foreach ($fs as $f) {
                $f = trim($f);
                $ft .= ($ft == '' ? "`{$f}`" : ",`{$f}`");
            }
            $fieldname .= "{$ft}) ";
        }
        $this->searchParameters[$c]['field'] = $fieldname;
        $this->searchParameters[$c]['value'] = $fieldvalue;
        $this->searchParameters[$c]['condition'] = $condition;
        $this->searchParameters[$c]['mode'] = $linkmode;
    }

    // 获取搜索条件
    public function GetSearchQuery()
    {
        $wquery = '';
        if (count($this->searchParameters) == 0) {
            return '';
        } else {
            foreach ($this->searchParameters as $k => $v) {
                if (preg_match("/like/i", $v['condition'])) {
                    $v['value'] = preg_replace("/like/i", $v['value'], $v['condition']);
                }
                $v['condition'] = preg_replace("/%/", '', $v['condition']);
                if ($wquery == '') {
                    if (!preg_match("/\./", $v['field'])) {
                        $v['field'] = "{$v['field']}";
                    }

                    $wquery .= "WHERE " . $v['field'] . " {$v['condition']} '{$v['value']}' ";
                } else {
                    if (!preg_match("/\./", $v['field'])) {
                        $v['field'] = "{$v['field']}";
                    }

                    $wquery .= $v['mode'] . " " . $v['field'] . " {$v['condition']} '{$v['value']}' ";
                }
            }
        }
        return $wquery;
    }

    //把从表单传递回来的数值进行处理
    public function GetData($fname)
    {
        $reValue = '';
        $ftype = $this->fields[$fname]['type'];
        $GLOBALS[$fname] = isset($GLOBALS[$fname]) ? $GLOBALS[$fname] : @$GLOBALS['request']->forms[$fname];
        //二进制单独处理
        if (in_array($ftype, $this->binTypes)) {
            return $this->GetBinData($fname);
        }
        //没有这个变量返回默认值
        else if (!isset($GLOBALS[$fname])) {
            if (isset($this->fields[$fname]['default'])) {
                return $this->fields[$fname]['default'];
            } else {
                if (in_array($ftype, $this->intTypes) || in_array($ftype, $this->floatTypes)) {
                    return 0;
                } else if (in_array($ftype, $this->charTypes) || in_array($ftype, $this->textTypes)) {
                    return '';
                } else {
                    return 'NULL';
                }
            }
        }
        //处理整数
        else if (preg_match("#YEAR|INT#", $ftype)) {
            // $temp = isset($GLOBALS[$fname][0])? $GLOBALS[$fname][0] : 0;
            $negTag = is_int($GLOBALS[$fname]) && $GLOBALS[$fname] < 0 ? '-' : $GLOBALS[$fname];
            $reValue = preg_replace("#[^0-9]#", '', $GLOBALS[$fname]);
            $reValue = empty($reValue) ? 0 : intval($reValue);
            if ($negTag == '-' && !$this->fields[$fname]['unsigned']
                && $reValue != 0 && $ftype != 'YEAR'
            ) {
                $reValue = intval('-' . $reValue);
            }
        }
        //处理小数类型
        else if (in_array($ftype, $this->floatTypes)) {
            $negTag = $GLOBALS[$fname][0];
            $reValue = preg_replace("#[^0-9\.]|^\.#", '', $GLOBALS[$fname]);
            $reValue = empty($reValue) ? 0 : doubleval($reValue);
            if ($negTag == '-' && !$this->fields[$fname]['unsigned'] && $reValue != 0) {
                $reValue = intval('-' . $reValue);
            }
        }
        //字符串类型
        else if (in_array($ftype, $this->charTypes)) {
            $reValue = cn_substrR($this->StringSafe($GLOBALS[$fname]), $this->fields[$fname]['length']);
        }
        //文本类型
        else if (in_array($ftype, $this->textTypes)) {
            $reValue = $this->StringSafe($GLOBALS[$fname]);
        }
        //SET类型
        else if ($ftype == 'SET') {
            $sysSetArr = explode(',', $this->fields[$fname]['em']);
            if (!is_array($GLOBALS[$fname])) {
                $setArr[] = $GLOBALS[$fname];
            } else {
                $setArr = $GLOBALS[$fname];
            }
            $reValues = array();
            foreach ($setArr as $a) {
                if (in_array($a, $sysSetArr)) {
                    $reValues[] = $a;
                }

            }
            $reValue = count($reValues) == 0 ? 'NULL' : join(',', $reValues);
        }
        //枚举类型
        else if ($ftype == 'ENUM') {
            $sysEnumArr = explode(',', $this->fields[$fname]['em']);
            if (in_array($GLOBALS[$fname], $sysEnumArr)) {
                $reValue = $GLOBALS[$fname];
            } else {
                $reValue = 'NULL';
            }

        }
        //时间日期类型
        else if (in_array($ftype, $this->dateTypes)) {
            if ($ftype == 'TIMESTAMP') {
                $reValue = strtotime($GLOBALS[$fname]);
            } else {
                $reValue = preg_replace("#[^0-9 :-]#", '', $GLOBALS[$fname]);
            }
        }
        return $reValue;
    }

    //对请求的字符串进行安全处理
    public function StringSafe($str, $safestep = -1)
    {
        $safestep = ($safestep > -1) ? $safestep : $this->stringSafe;
        //过滤危险的HTML(默认级别)
        if ($safestep == 1) {
            $str = preg_replace("#script:#i", "ｓｃｒｉｐｔ：", $str);
            $str = preg_replace("#<[\/]{0,1}(link|meta|ifr|fra|scr)[^>]*>#isU", '', $str);
            $str = preg_replace("#[\r\n\t ]{1,}#", ' ', $str);
            return $str;
        }
        //完全禁止HTML
        //并转换一些不安全字符串（如：eval(、union、CONCAT(、--、等）
        else if ($this->stringSafe == 2) {
            $str = addslashes(dede_htmlspecialchars(stripslashes($str)));
            $str = preg_replace("#eval#i", 'ｅｖａｌ', $str);
            $str = preg_replace("#union#i", 'ｕｎｉｏｎ', $str);
            $str = preg_replace("#concat#i", 'ｃｏｎｃａｔ', $str);
            $str = preg_replace("#--#", '－－', $str);
            $str = preg_replace("#[\r\n\t ]{1,}#", ' ', $str);
            return $str;
        }
        //不作安全处理
        else {
            return $str;
        }
    }
    //保存二进制文件数据
    //为了安全起见，对二进制数据保存使用base64编码后存入
    public function GetBinData($fname)
    {
        $lurdtmp = DEDEDATA . '/lurdtmp';
        if (!isset($_FILES[$fname]['tmp_name']) || !is_uploaded_file($_FILES[$fname]['tmp_name'])) {
            return '';
        } else {
            $tmpfile = $lurdtmp . '/' . md5(time() . mt_rand(1000, 5000)) . '.tmp';
            $rs = move_uploaded_file($_FILES[$fname]['tmp_name'], $tmpfile);
            if (!$rs) {
                return '';
            }

            $fp = fopen($tmpfile, 'r');
            $data = base64_encode(fread($fp, filesize($tmpfile)));
            fclose($fp);
            return $data;
        }
    }

    //格式化浮点数字
    public function FormatFloat($fvalue, $ftype = '')
    {
        if ($ftype == '') {
            $ftype = '%0.4f';
        }

        return sprintf($ftype, $fvalue);
    }

    //获得默认时间格式
    public function GetDateTimeDf($ftype)
    {
        if ($ftype == 'DATE') {
            return 'Y-m-d';
        } else if ($ftype == 'TIME') {
            return 'H:i:s';
        } else if ($ftype == 'YEAR') {
            return 'Y';
        } else {
            return 'Y-m-d H:i:s';
        }

    }

    //格式化日期
    public function FormatDate($fvalue, $ftype, $fformat = '')
    {
        if ($ftype == 'INT' || $ftype = 'TIMESTAMP') {
            return MyDate($fvalue, $fformat);
        } else {
            return $fvalue;
        }

    }

}
